/* eslint-disable eqeqeq */
'use strict';

// +----------------------------------------------------------------------
// | CmsWing [ 网站内容管理框架 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2015 http://www.cmswing.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: arterli <arterli@qq.com>
// +----------------------------------------------------------------------
/**
 * this file will be loaded before server started
 * you can define global functions used in controllers, models, templates
 */

/**
 * use global.xxx to define global functions
 *
 * global.fn1 = function(){
 *
 * }
 *
 *global.xxx = async () => {
 *   let data = await Promise.resolve(111)
 *}
 */

/**
 * ip转数字
 * @param {*} ip ?
 * @return {number} ?
 */
global._ip2int = function(ip) {
    let num = 0;
    ip = ip.split('.');
    num = Number(ip[0]) * 256 * 256 * 256 + Number(ip[1]) * 256 * 256 + Number(ip[2]) * 256 + Number(ip[3]);
    num = num >>> 0;
    return num;
};

/**
 * 数字转ip
 * @param {*} num ?
 * @return {string|*} ?
 */
global._int2iP = function(num) {
    const tt = [];
    tt[0] = (num >>> 24) >>> 0;
    tt[1] = ((num << 8) >>> 24) >>> 0;
    tt[2] = (num << 16) >>> 24;
    tt[3] = (num << 24) >>> 24;
    return String(tt[0]) + '.' + String(tt[1]) + '.' + String(tt[2]) + '.' + String(tt[3]);
};

/**
 * 密码加密
 * @param {String} password 加密的密码
 * @param {String} md5encoded true-密码不加密，默认加密
 * @return {String} 结果
 */
global.encryptPassword = function(password, md5encoded) {
    md5encoded = md5encoded || false;
    password = md5encoded ? password : think.md5(password);
    return think.md5(think.md5('www.cmswing.com') + password + think.md5('Arterli'));
};

/**
 * 数组去重
 * @param {Array} arr 需要去重的数组
 * @return {Array} 去重后的数组
 */
global.unique = function(arr) {
    return Array.from(new Set(arr));
};

/**
 * 判断查找的字符串在字符串是否存在
 * @param {String} stringToSearch 查找的字符串
 * @param {Array} arrayToSearch 被查找的数组
 * @return {boolean} 结果
 */
global.in_array = function(stringToSearch, arrayToSearch) {
    for (let s = 0; s < arrayToSearch.length; s++) {
        const thisEntry = arrayToSearch[s].toString();

        if (thisEntry == stringToSearch) {
            return true;
        }
    }
    return false;
};

/**
 * 格式化时间
 * @param {String} dateStr 日期字符串
 * @param {Boolean} sec 是否显示秒
 * @return {string} 格式化后的时间
 */
global.times = function(dateStr, sec) {
    let time;
    const date = new Date(dateStr);
    const y = date.getFullYear();
    let M = date.getMonth() + 1;
    M = M < 10 ? '0' + M : M;
    let d = date.getDate();
    d = d < 10 ? '0' + d : d;
    let h = date.getHours();
    h = h < 10 ? '0' + h : h;
    let m = date.getMinutes();
    m = m < 10 ? '0' + m : m;
    let s = date.getSeconds();
    s = s < 10 ? '0' + s : s;
    if (sec) {
        time = y + '-' + M + '-' + d + ' ' + h + ':' + m + ':' + s;
    } else {
        time = y + '-' + M + '-' + d + ' ' + h + ':' + m;
    }

    return time;
};

/**
 * 排序函数
 * @param {Integer} v 值1
 * @param {Integer} w 值2
 * @return {Integer} 结果
 */
function sort_node(v, w) {
    return v.sort - w.sort;
}

/**
 * 排序函数
 * @param {Integer} v 值1
 * @param {Integer} w 值2
 * @return {Integer} 结果
 */
function sort_node1(v, w) {
    return w.sort - v.sort;
}

/**
 * global get_children
 * 获取子集分类 （这里是获取所有子集）
 * @param {*} nodes 未知
 * @param {*} parent 未知
 * @param {*} sn 未知
 */
global.get_children = function(nodes, parent, sn = 0) {
    // console.log(11);
    let children = [];
    let last = [];
    /* 未访问的节点 */
    /*
     * 获取根分类列表。
     * 创建一个虚拟父级分类亦可
     **/
    let node = null;
    for (const i in nodes) {
        node = nodes[i];
        if (node.pid === parent) {
            node.deep = 0;
            children.push(node);
        } else {
            last.push(node);
        }
    }
    if (sn === 0) {
        children.sort(sort_node);
    } else {
        children.sort(sort_node1);
    }

    /* 同级排序 */
    let jumper = 0;
    let stack = children.slice(0);
    /* easy clone */

    while (stack.length > 0 &&
    /* just in case */ jumper++ < 1000) {
        const shift_node = stack.shift();
        const list = [];
        /* 当前子节点列表 */
        const last_static = last.slice(0);
        last = [];
        for (const i in last_static) {
            node = last_static[i];
            if (node.pid === shift_node.id) {
                node.deep = shift_node.deep + 1;
                list.push(node);
            } else {
                last.push(node);
            }
        }
        if (sn === 0) {
            list.sort(sort_node);
        } else {
            list.sort(sort_node1);
        }

        for (const i in list) {
            node = list[i];
            stack.push(node);
            children.push(node);
        }
    }
    /*
     * 有序树非递归前序遍历
     *
     * */
    stack = [];
    /* 前序操作栈 - 分类编号 */
    let top = null;
    /* 操作栈顶 */
    let tree = children.slice(0);
    /* 未在前序操作栈内弹出的节点 */
    let has_child = false;
    /* 是否有子节点，如无子节点则弹出栈顶 */
    children = [];
    /* 清空结果集 */
    jumper = 0;
    last = [];
    /* 未遍历的节点 */
    let current = null;
    /* 当前节点 */
    stack.push(parent);
    /* 建立根节点 */

    while (stack.length > 0) {
        if (jumper++ > 1000) {
            break;
        }
        top = stack[stack.length - 1];
        has_child = false;
        last = [];

        for (const i in tree) {
            current = tree[i];
            if (current.pid === top) {
                top = current.id;
                stack.push(top);
                children.push(current);
                has_child = true;
            } else {
                last.push(current);
            }
        }
        tree = last.slice(0);
        if (!has_child) {
            stack.pop();
            top = stack[stack.length - 1];
        }
    }
    return children;
};
/**
 * obj_values(obj);
 * 获取对象中的所有的值，并返回数组
 * @param obj
 * @returns {Array}
 */
/* global obj_values */
global.obj_values = function(obj) {
    const objkey = Object.keys(obj);
    const objarr = [];
    objkey.forEach(key => {
        objarr.push(obj[key]);
    });
    return objarr;
};

/**
 * 判断对象是否相等
 * @param {*} a 未知
 * @param {*} b 未知
 * @return {Boolean} 结果
 */
global.isObjectValueEqual = function(a, b) {
    // Of course, we can do it use for in
    // Create arrays of property names
    const aProps = Object.getOwnPropertyNames(a);
    const bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different,
    // objects are not equivalent
    if (aProps.length !== bProps.length) {
        return false;
    }

    for (let i = 0; i < aProps.length; i++) {
        const propName = aProps[i];

        // If values of same property are not equal,
        // objects are not equivalent
        if (a[propName] !== b[propName]) {
            return false;
        }
    }

    // If we made it this far, objects
    // are considered equivalent
    return true;
};

/**
 * 删除左右两端的空格
 * @param {String} str 字符串
 * @return {*|void|string|XML} 结果
 */
global.trim = function(str) {
    return str.replace(/(^\s*)|(\s*$)/g, '');
};

/**
 * 分析枚举类型配置值 格式 a:名称1,b:名称2
 * @param {String} str 字符串
 * @param {String} sep 分隔符
 * @return {*} 结果
 */
global.parse_config_attr = function(str, sep = ':') {
    let strs;
    if (str.search(/\r\n/ig) > -1) {
        strs = str.split('\r\n');
    } else if (str.search(/,/ig) > -1) {
        strs = str.split(',');
    } else if (str.search(/\n/ig) > -1) {
        strs = str.split('\n');
    } else {
        strs = [ str ];
    }
    if (think.isArray(strs)) {
        const obj = {};
        strs.forEach(n => {
            n = n.split(sep);
            obj[n[0]] = n[1];
        });
        return obj;
    }
};

/**
 * 解析类型属性
 * @param {String} str 字符串
 * @return {Array} 结果
 */
global.parse_type_attr = function(str) {
    let strs;
    if (str.search(/\r\n/ig) > -1) {
        strs = str.split('\r\n');
    } else if (str.search(/,/ig) > -1) {
        strs = str.split(',');
    } else if (str.search(/\n/ig) > -1) {
        strs = str.split('\n');
    } else {
        strs = [ str ];
    }
    if (think.isArray(strs)) {
        const arr = [];
        for (let v of strs) {
            const obj = {};
            v = v.split(':');
            if (!think.isEmpty(v[0]) && !think.isEmpty(v[1])) {
                obj.id = v[0];
                obj.name = v[1];
                if (obj.id.split('.').length === 1) {
                    obj.pid = 0;
                } else {
                    obj.pid = obj.id.split('.').splice(0, obj.id.split('.').length - 1).join('.');
                }
                arr.push(obj);
            }
        }
        // console.log(arr);
        const tree = global.arr_to_tree(arr, 0);
        // think.log(tree);
        return tree;
    }
};

/**
 * 删除左边的空格
 * @param {String} str 需要去除的字符串
 * @return {*|void|string|XML} 结果
 */
global.ltrim = function(str) {
    return str.replace(/(^\s*)/g, '');
};

/**
 * 删除右边的空格
 * @param {String} str 需要去除的字符串
 * @return {*|void|string|XML} 结果
 */
global.rtrim = function(str) {
    return str.replace(/(\s*$)/g, '');
};

/**
 * 把返回的数据集转换成Tree
 * @param {array} data 要转换的数据集
 * @param {string} pid parent标记字段
 * @return {array} 结果
 */
global.arr_to_tree = function(data, pid) {
    const result = [];
    let temp;
    const length = data.length;
    for (let i = 0; i < length; i++) {
        if (data[i].pid === pid) {
            result.push(data[i]);
            temp = global.arr_to_tree(data, data[i].id);
            if (temp.length > 0) {
                data[i].children = temp;
                data[i].chnum = data[i].children.length;
            }
        }
    }
    return result;
};

/**
 * 计算分类信息当前状态
 * @param {Array} arr 数据
 * @return {Array} 结果
 */
global.sanjiao = arr => {
    const result = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        result.push(result[i - 1] !== undefined ? result[i - 1] + '.' + arr[i] : arr[i]);
    }
    return result;
};

/**
 * @param {*} data 未知
 * @param {Integer} pid 父ID
 * @return {Arrray} 结果
 */
global.sub_cate = function(data, pid) {
    const result = [];
    let temp;
    const length = data.length;
    for (let i = 0; i < length; i++) {
        if (data[i].pid === pid) {
            // console.log(data[i]);
            result.push(data[i].id);
            temp = global.sub_cate(data, data[i].id);
            if (temp.length > 0) {
                result.push(temp.join(','));
            }
        }
    }
    return result;
};

/**
 * 获取属性类型信息
 * @param {String} type 类型
 * @return {String} 结果
 */
global.get_attribute_type = function(type) {
    // TODO 可以加入系统配置
    const _type = {
        num: [ '数字', 'int(10) unsigned NOT NULL' ],
        string: [ '字符串', 'varchar(255) NOT NULL' ],
        textarea: [ '文本框', 'text NOT NULL' ],
        date: [ '日期', 'bigint(13) NOT NULL' ],
        datetime: [ '时间', 'bigint(13) NOT NULL' ],
        bool: [ '布尔', 'tinyint(2) NOT NULL' ],
        select: [ '枚举', 'char(50) NOT NULL' ],
        radio: [ '单选', 'char(10) NOT NULL' ],
        checkbox: [ '多选', 'varchar(100) NOT NULL' ],
        editor: [ '编辑器', 'text NOT NULL' ],
        picture: [ '上传图片', 'int(10) unsigned NOT NULL' ],
        file: [ '上传附件', 'int(10) unsigned NOT NULL' ],
        suk: [ '商品规格', 'text NOT NULL' ],
        pics: [ '多图上传', 'varchar(255) NOT NULL' ],
        price: [ '价格', 'varchar(255) NOT NULL' ],
        freight: [ '运费', 'varchar(255) NOT NULL' ],
        keyword: [ '关键词', 'varchar(255) NOT NULL' ],
        relation: [ '关联', 'varchar(100) NOT NULL' ],
        atlas: [ '图集', 'text NOT NULL' ],
    };
    return type ? _type[type][0] : _type;
};

/**
 * 时间戳格式化 dateformat()
 * @param {String} extra 'Y-m-d H:i:s'
 * @param {Number} date  时间戳
 * @return {String} '2015-12-17 15:39:44'
 */
global.dateformat = function(extra, date) {
    const D = new Date(date);
    const time = {
        Y: D.getFullYear(),
        m: D.getMonth() + 1,
        d: D.getDate(),
        H: D.getHours(),
        i: D.getMinutes(),
        s: D.getSeconds(),
    };
    const key = extra.split(/\W/);
    let _date;
    for (const k of key) {
        time[k] = time[k] < 10 ? '0' + time[k] : time[k];
        _date = extra.replace(k, time[k]);
        extra = _date;
    }
    return _date;
};

/**
 * 判断字符串在数组中是否存在
 * @param {Array} arr 被搜索的数组
 * @param {String} str 搜索的字符串
 * @return {Integer|Boolean} -1,数组索引,false
 */
global.array_search = function(arr, str) {
    // 如果可以的话，调用原生方法
    if (arr && arr.indexOf) {
        return arr.indexOf(str);
    }

    const len = arr.length;
    for (let i = 0; i < len; i++) {
        // 定位该元素位置
        if (arr[i] === str) {
            return i;
        }
    }

    // 数组中不存在该元素
    return false;
};

/**
 * 找出两个数组中不同的值
 * @param {Array} arr1 数组1
 * @param {Array} arr2 数组2
 * @return {Array} 结果
 */
global.array_diff = function(arr1, arr2) {
    // var arr1 = ["i", "b", "c", "d", "e", "f","x",""]; //数组A
    // var arr2 = ["a", "b", "c", "d", "e", "f", "g"];//数组B
    const temp = []; // 临时数组1
    const temparray = [];// 临时数组2
    for (let i = 0; i < arr2.length; i++) {
        temp[arr2[i]] = true;// 巧妙地方：把数组B的值当成临时数组1的键并赋值为真
    }
    for (let i = 0; i < arr1.length; i++) {
        if (!temp[arr1[i]]) {
            temparray.push(arr1[i]);// 巧妙地方：同时把数组A的值当成临时数组1的键并判断是否为真，如果不为真说明没重复，就合并到一个新数组里，这样就可以得到一个全新并无重复的数组
        }
    }

    return temparray;
};

/**
 * 未知
 * @param {*} data 未知
 * @param {*} grid 未知
 * @param {String} controller 控制器名称
 * @return {*} 未知
 */
global.get_list_field = function(data, grid, controller) {
    const data2 = {};
    let value;

    // 获取当前字段数据
    // console.log(grid);
    for (const field of grid.field) {
        let temp;
        const array = field.split('|');// TODO
        // console.log(array);
        temp = data[array[0]];
        // console.log(temp);
        // 函数支持
        if (!think.isEmpty(array[1])) {
            temp = call_user_func(array[1], temp);
        }
        data2[array[0]] = temp;
    }
    // console.log(data2);
    if (!think.isEmpty(grid.format)) {
        // value  =   preg_replace_callback('/\[([a-z_]+)\]/', function($match) use($data2){return $data2[$match[1]];}, $grid['format']);
    } else {
        value = data2[Object.keys(data2)];
    }

    // 链接支持
    if (grid.field[0] === 'title' && data.type === '目录') {
        // 目录类型自动设置子文档列表链接
        grid.href = '[LIST]';
    } else if (grid.field[0] === 'title') {
        grid.href = '[EDIT]';
    }

    if (!think.isEmpty(grid.href)) {
        const links = grid.href.split(',');

        const val = [];
        for (const link of links) {
            const array = link.split('|');
            const href = array[0];

            // console.log(href);
            const matches = href.match(/^\[([a-z_]+)\]$/);
            if (matches) {
                val.push(data2[matches[1]]);
                // console.log(val);
            } else {
                const show = !think.isEmpty(array[1]) ? array[1] : value;
                // console.log(show)
                // 替换系统特殊字符串
                const hrefs = {
                    '[DELETE]': 'setstatus/?status=-1&ids=[id]',
                    '[EDIT]': 'edit/?id=[id]&model=[model_id]&cate_id=[category_id]',
                    '[LIST]': 'index/?pid=[id]&model=[model_id]&cate_id=[category_id]',
                };
                const match = hrefs[href].match(/\[(\S+?)\]/g);

                const u = [];
                for (const k of match) {
                    const key = k.replace(/(^\[)|(\]$)/g, '');
                    u.push(data[key]);
                }

                const query = str_replace(match, u, hrefs[href]);
                const href1 = `/${controller}/${query}`;

                if (href === '[DELETE]') {
                    val.push('<a href="' + href1 + '" class="text-info ajax-get confirm">' + show + '</a> ');
                } else {
                    val.push('<a href="' + href1 + '" class="text-info">' + show + '</a> ');
                }
            }
        }
        value = val.join(' ');
    }

    return value;
};

/**
 * 获取行为类型
 * @param intger type 类型
 * @param bool all 是否返回全部类型
 * @author arterli <arterli@qq.com>
 */
/* global get_action_type */
global.get_action_type = function(type, all) {
    all = all || false;
    const list = {
        1: '系统',
        2: '用户',
    };
    if (all) {
        return list;
    }
    return list[type];
};

/**
 * 返回一个自定义用户函数给出的第一个参数
 *  call_user_func（回调 函数名， [参数]）
 * @param cb  函数名
 * @param params 数组格式传入参数
 */
/* global call_user_func */
global.call_user_func = function(cb, params) {
    // eslint-disable-next-line no-eval
    const func = eval(cb);
    if (!think.isArray(params)) {
        params = [ params ];
    }
    return func.apply(cb, params);
};

/**
 *根据uid获取用户昵称
 * @param uid 用户id
 * @returns Promise {*}
 */
/* global get_nickname */
global.get_nickname = async uid => {
    // console.log(uid);
    // let data = await think.model('member', think.config("model")).cache(1000).get_nickname(uid);
    const data = await think.model('cmswing/member').get_nickname(uid);
    return data;
};
// 时间格式
/* global time_format */
global.time_format = time => {
    return global.dateformat('Y-m-d H:i:s', time);
};
/* global str_replace()
 * str_replace(条件[]，替换内容[],被替换的内容)
 * @param search
 * @param replace
 * @param subject
 * @param count
 * @returns {*}
 */
/* global str_replace */
global.str_replace = function(search, replace, subject, count) {
    let i = 0,
        j = 0,
        temp = '',
        repl = '',
        sl = 0,
        fl = 0,
        s = subject;
    const f = [].concat(search),
        r = [].concat(replace),
        ra = r instanceof Array,
        sa = s instanceof Array;
    s = [].concat(s);
    if (count) {
        this.window[count] = 0;
    }

    for (i = 0, sl = s.length; i < sl; i++) {
        if (s[i] === '') {
            continue;
        }
        for (j = 0, fl = f.length; j < fl; j++) {
            temp = s[i] + '';
            repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];
            s[i] = (temp).split(f[j]).join(repl);
            if (count && s[i] !== temp) {
                this.window[count] += (temp.length - s[i].length) / f[j].length;
            }
        }
    }
    return sa ? s : s[0];
};
/**
 * 获取文档地址
 * @param {*} name 文档表示
 * @param {*} id   文档id
 * @return {*} 结果
 */
global.get_url = (name, id) => {
    if (!think.isEmpty(name)) {
        return `/p/${name}.html`;
    }
    return `/p/${id}.html`;

};

/**
 * 未知
 * @param {*} id 未知
 * @return {*} 未知
 */
global.get_pdq = id => {
    return global.parse_config_attr(think.config('ext.attachment.pdn'), '@')[id];
};

/**
 * 获取文档封面图片
 * @param {int} cover_id 未知
 * @param {string} field 未知
 * @return {*} 完整的数据  或者  指定的field字段值
 * @author arterli <arterli@qq.com>
 */
global.get_cover = async (cover_id, field) => {
    if (think.isEmpty(cover_id)) {
        return false;
    }
    const picture = await think.model('ext_attachment_pic').where({ status: 1 }).find(cover_id);
    return think.isEmpty(field) ? picture : picture[field];
};

/**
 * /0/w/<LongEdge>/h/<ShortEdge> 	限定缩略图的长边最多为<LongEdge>，短边最多为<ShortEdge>，进行等比缩放，不裁剪。如果只指定 w 参数则表示限定长边（短边自适应），只指定 h 参数则表示限定短边（长边自适应）。
 * /1/w/<Width>/h/<Height> 	限定缩略图的宽最少为<Width>，高最少为<Height>，进行等比缩放，居中裁剪。转后的缩略图通常恰好是 <Width>x<Height> 的大小（有一个边缩放的时候会因为超出矩形框而被裁剪掉多余部分）。如果只指定 w 参数或只指定 h 参数，代表限定为长宽相等的正方图。
 * /2/w/<Width>/h/<Height> 	限定缩略图的宽最多为<Width>，高最多为<Height>，进行等比缩放，不裁剪。如果只指定 w 参数则表示限定宽（长自适应），只指定 h 参数则表示限定长（宽自适应）。它和模式0类似，区别只是限定宽和高，不是限定长边和短边。从应用场景来说，模式0适合移动设备上做缩略图，模式2适合PC上做缩略图。
 * /3/w/<Width>/h/<Height> 	限定缩略图的宽最少为<Width>，高最少为<Height>，进行等比缩放，不裁剪。如果只指定 w 参数或只指定 h 参数，代表长宽限定为同样的值。你可以理解为模式1是模式3的结果再做居中裁剪得到的。
 * /4/w/<LongEdge>/h/<ShortEdge> 	限定缩略图的长边最少为<LongEdge>，短边最少为<ShortEdge>，进行等比缩放，不裁剪。如果只指定 w 参数或只指定 h 参数，表示长边短边限定为同样的值。这个模式很适合在手持设备做图片的全屏查看（把这里的长边短边分别设为手机屏幕的分辨率即可），生成的图片尺寸刚好充满整个屏幕（某一个边可能会超出屏幕）。
 * /5/w/<LongEdge>/h/<ShortEdge> 	限定缩略图的长边最少为<LongEdge>，短边最少为<ShortEdge>，进行等比缩放，居中裁剪。如果只指定 w 参数或只指定 h 参数，表示长边短边限定为同样的值。同上模式4，但超出限定的矩形部分会被裁剪。
 * @param {*} id 未知
 * @param {*} m 未知
 * @param {*} w 宽
 * @param {*} h 高
 */
global.get_pic = async (id, m = null, w = null, h = null) => {
    if (think.isEmpty(id)) {
        return '/static/noimg.jpg';
    }
    const map = {};
    map.status = 1;
    if (think.isNumberString(id)) {
        map.id = id;
    } else {
        map.path = id;
    }
    const picture = await think.model('ext_attachment_pic').where(map).cache(1000 * 1000)
        .find();
    if (think.isEmpty(picture)) {
        return '/static/noimg.jpg';
    }
    let q = '';
    if (picture.type > 0) {
        if (m != null) {
            m = '/' + m;
        } else {
            m = '';
        }
        if (w != null) {
            w = '/w/' + w;
        } else {
            w = '';
        }
        if (h != null) {
            h = '/h/' + h;
        } else {
            h = '';
        }
        if (m !== '' || w !== '' || h !== '') {
            q = `?imageView2${m}${w}${h}`;
        }

        return `${global.get_pdq(picture.type)}/${picture.path}${q}`;
    }
    return picture.path;

};
/**
 * 获取多图封面
 * @param {array} arr_id 未知
 * @param {string} field 未知
 * @return {*} 完整的数据或者 指定的field字段值
 * @author arterli <arterli@qq.com>
 */
global.get_pics_one = async (arr_id, field) => {
    if (think.isEmpty(arr_id)) {
        return false;
    }
    const arr = arr_id.split(',');
    return global.get_cover(arr[0], field);
};

/**
 * 未知
 * @param {String} price 价格{present_price:100,discount_price:80}
 * @return {String} html
 */
global.formatprice = function(price) {
    const pr = JSON.parse(price);
    let present_price;

    if (think.isNumber(pr.present_price)) {
        pr.present_price = pr.present_price.toString();
    }
    price = pr.present_price.split('-');
    if (price.length > 1) {
        present_price = global.formatCurrency(price[0]) + '-' + global.formatCurrency(price[1]);
    } else {
        present_price = global.formatCurrency(price[0]);
    }
    if (pr.discount_price === 0) {
        return `<span class="text-xs"><span class="text-danger">现价:￥${present_price}</span></span>`;
    }
    return `<span class="text-xs"><span class="text-danger">现价:￥${present_price}</span> <br>原价:￥${global.formatCurrency(pr.discount_price)}</span>`;

};

/**
 * 获取价格格式化并格式化
 * @param {String} price JSON.stringify数据
 * @param {Integer} type 类型
 * @return {String} 价格
 */
global.get_price_format = function(price, type) {
    const pr = JSON.parse(price);

    if (type === 1) {
        if (think.isNumber(pr.present_price)) {
            pr.present_price = pr.present_price.toString();
        }
        const prices = pr.present_price.split('-');
        let present_price;
        if (prices.length > 1) {
            present_price = global.formatCurrency(prices[0]) + '-' + global.formatCurrency(prices[1]);
        } else {
            present_price = global.formatCurrency(prices[0]);
        }
        price = present_price;
    } else {
        if (pr.discount_price === 0) {
            price = '';
        } else {
            price = global.formatCurrency(pr.discount_price);
        }
    }
    return price;
};

/**
 * 获取价格不格式化
 * @param {String} price JSON.stringify数据
 * @param {Integer} type 类型
 * @return {String} 价格
 */
global.get_price = function(price, type) {
    if (price) {
        price = JSON.parse(price);
        if (type === 1) {
            return price.present_price;
        }
        if (price.discount_price === 0) {
            return '';
        }
        return price.discount_price;


    }
};

/**
 * 将数值四舍五入(保留2位小数)后格式化成金额形式
 * @param {Number|String} num 数值(Number或者String)
 * @return {*} 金额格式的字符串,如'1,234,567.45'
 */
global.formatCurrency = function(num) {
    num = Number(num.toString().replace(/\$|\,/g, ''));
    if (isNaN(num)) { num = '0'; }
    const sign = (num === (num = Math.abs(num)));
    num = Math.floor(num * 100 + 0.50000000001);
    let cents = num % 100;
    num = Math.floor(num / 100).toString();
    if (cents < 10) { cents = '0' + cents; }
    for (let i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {
        num = num.substring(0, num.length - (4 * i + 3)) + ',' +
            num.substring(num.length - (4 * i + 3));
    }
    return (((sign) ? '' : '-') + num + '.' + cents);
};

/**
 * 将数值四舍五入(保留1位小数)后格式化成金额形式
 * @param {Number|String} num 数值(Number或者String)
 * @return {*} 金额格式的字符串,如'1,234,567.4'
 */
global.formatCurrencyTenThou = function(num) {
    num = num.toString().replace(/\$|\,/g, '');
    if (isNaN(num)) { num = '0'; }
    const sign = (num === (num = Math.abs(num)));
    num = Math.floor(num * 10 + 0.50000000001);
    const cents = num % 10;
    num = Math.floor(num / 10).toString();
    for (let i = 0; i < Math.floor((num.length - (1 + i)) / 3); i++) {
        num = num.substring(0, num.length - (4 * i + 3)) + ',' +
            num.substring(num.length - (4 * i + 3));
    }
    return (((sign) ? '' : '-') + num + '.' + cents);
};

/**
 * 获取商品suk suk, arr:类型数组
 * @param {*} suk 未知
 * @param {Array} arr 未知
 * @return {*} 未知
 */
global.getsuk = function(suk, arr) {
    let suk_;
    suk.forEach(function(v) {
        if (v.name === arr[0]) {
            if (v.ch) {
                v.ch.forEach(function(v_) {
                    if (v_.name === arr[1]) {
                        if (v_.ch) {
                            v_.ch.forEach(function(v__) {
                                if (v__.name === arr[2]) {
                                    suk_ = think.extend(v__, v_, v);
                                }
                            });
                        } else {
                            suk_ = think.extend(v_, v);
                        }
                    }
                });
            } else {
                suk_ = v;
            }
        }
    });
    return suk_;
};

/**
 * 构建微信菜单数据结构
 * @param {*} data 未知
 * @return {*} {{menu: {button: Array}}}
 */
global.createSelfMenu = function(data) {
    const menu = {
        menu: {
            button: [],
        },
    };
    const button = [];
    for (let i = 0; i < data.length; i++) {
        if (data[i].pid === 0) {
            const item = {
                id: data[i].id,
                m_id: data[i].m_id,
                pid: data[i].pid,
                type: data[i].type,
                name: data[i].name,
                sort: data[i].sort,
                sub_button: [],
            };
            menu.menu.button.push(item);
            button.push(item);
        }
    }
    for (let x = 0; x < button.length; x++) {
        for (let y = 0; y < data.length; y++) {
            if (data[y].pid === button[x].m_id) {
                const sitem = {
                    type: data[y].type,
                    m_id: data[y].m_id,
                    sort: data[y].sort,
                    name: data[y].name,
                    url: data[y].url,
                    media_id: data[y].media_id,
                };
                button[x].sub_button.push(sitem);
            }
        }
    }
    return menu;
};

/**
 * 微信创建自定义菜单接口
 * 数据构建
 */

global.buildselfmenu = function(data) {
    const menu = {
        button: [],
    };
    const button = [];
    for (let i = 0; i < data.length; i++) {
        if (data[i].pid === 0) {
            const item = {
                id: data[i].id,
                m_id: data[i].m_id,
                pid: data[i].pid,
                type: data[i].type,
                name: data[i].name,
                sort: data[i].sort,
                sub_button: [],
            };
            menu.menu.button.push(item);
            button.push(item);
        }
    }
    for (let x = 0; x < button.length; x++) {
        for (let y = 0; y < data.length; y++) {
            if (data[y].pid === button[x].m_id) {
                const sitem = {
                    type: data[y].type,
                    sort: data[y].sort,
                    name: data[y].name,
                    url: data[y].url,
                    media_id: data[y].media_id,
                };
                button[x].sub_button.push(sitem);
            }
        }
    }
    return menu;
};

/**
 * 验证是否为智能手机
 * @param {string} agent :this.userAgent;
 * @return {boolean} 未知
 */
global.checkMobile = function(agent) {
    let flag = false;
    agent = agent.toLowerCase();
    const keywords = [ 'android', 'iphone', 'ipod', 'ipad', 'windows phone', 'mqqbrowser' ];

    // 排除 Windows 桌面系统
    if (!(agent.indexOf('windows nt') > -1) || (agent.indexOf('windows nt') > -1 && agent.indexOf('compatible; msie 9.0;') > -1)) {
        // 排除苹果桌面系统
        if (!(agent.indexOf('windows nt') > -1) && !agent.indexOf('macintosh') > -1 && !(agent.indexOf('ipad') > -1)) {
            for (const item of keywords) {
                if (agent.indexOf(item) > -1) {
                    flag = true;
                    break;
                }
            }
        }
    }
    return flag;
};

/**
 * 验证时否是微信
 * @param {*} agent ?
 * @return {*} ?
 */
global.is_weixin = agent => {
    let flag = false;
    agent = agent.toLowerCase();
    // let key = ["mqqbrowser","micromessenger"];
    const key = [ 'micromessenger' ];
    // 排除 Windows 桌面系统
    if (!(agent.indexOf('windows nt') > -1) || (agent.indexOf('windows nt') > -1 && agent.indexOf('compatible; msie 9.0;') > -1)) {
        // 排除苹果桌面系统
        if (!(agent.indexOf('windows nt') > -1) && !agent.indexOf('macintosh') > -1) {
            for (const item of key) {
                if (agent.indexOf(item) > -1) {
                    flag = true;
                    break;
                }
            }
        }
    }
    return flag;
};

/**
 * ?
 * @param {*} time ?
 * @return {string} 'January 31, 2018 15:03:26'
 */
global.date_from = time => {
    // January 31, 2018 15:03:26
    const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ];
    const d = new Date(time);
    const month = months[d.getMonth()];
    const day = d.getDate();
    const year = d.getFullYear();
    const hour = d.getHours() < 10 ? `0${d.getHours()}` : d.getHours();
    const min = d.getMinutes() < 10 ? `0${d.getMinutes()}` : d.getMinutes();
    const sec = d.getSeconds() < 10 ? `0${d.getSeconds()}` : d.getSeconds();
    const res = `${month} ${day}, ${year} ${hour}:${min}:${sec}`;
    return res;
};

global.image_view = (str, w, m) => {
    const imgReg = /<img.*?(?:>|\/>)/gi;
    const srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
    const arr = str.match(imgReg);
    if (!think.isEmpty(arr)) {
        const narr = [];
        for (const img of arr) {
            const _img = img.match(srcReg);
            // console.log(_img);
            const nimg = _img[1] + '?imageView2/' + m + '/w/' + w;
            // console.log(nimg)
            const inputimg = _img.input.replace(_img[1], nimg);
            narr.push(inputimg);
        }
        return str_replace(arr, narr, str);
    }
    return str;

};

global.img_text_view = (str, w, h) => {
    // console.log(info);
    const imgReg = /<img.*?(?:>|\/>)/gi;
    const srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
    if (think.isEmpty(str)) {
        return [];
    }
    const arr = str.match(imgReg);
    if (!think.isEmpty(arr)) {
        const narr = [];
        for (const img of arr) {
            const _img = img.match(srcReg);
            // console.log(_img[1]);
            let nimg = _img[1];
            if (!think.isEmpty(w) && !think.isEmpty(h)) {
                nimg = _img[1] + '?imageView2/1/w/' + w + '/h/' + h;
            }
            // console.log(nimg)
            narr.push(nimg);
        }
        // console.log(narr);
        return narr;
    }
    return [];

};

/**
 * 获取文件信息
 * @param {*} file_id 文件id
 * @param {*} field 字段名,如果为空则返回整个记录集
 * @param {*} key ?
 * @return {*} ?
 */
global.get_file = async (file_id, field, key = false) => {
    if (think.isEmpty(file_id)) {
        return false;
    }
    const file = await think.model('ext_attachment_file').find(file_id);
    if (file.type > 0 && key && key !== 1) {
        file.savename = `${global.get_pdq(file.type)}/${file.savename}?download/${file.savename}`;
    } else if (file.type > 0 && key === 1) {
        file.savename = `${global.get_pdq(file.type)}/${file.savename}`;
    } else {
        file.savename = `${file.savepath}/${file.savename}`;
    }
    return think.isEmpty(field) ? file : file[field];
};

/**
 * 根据栏目ID获取栏目信息
 * @param {*} cid ?
 * @return {*} ?
 */
global.get_cate = async cid => {
    const column = await think.model('cmswing/category').get_all_category();
    for (const v of column) {
        if (v.id === cid) {
            // console.log(v)
            return v;
        }
    }
};

/**
 * 获取分类信息url
 * @param {*} id ?
 * @param {*} val ?
 * @param {*} arr ?
 * @param {*} http ?
 * @return {*} ?
 */
global.sort_url = (id, val, arr, http) => {
    // console.log(http.get(val))
    let url;
    url = `${val}_${id}`;
    for (const v of arr) {
        if (v.option.identifier !== val) {
            url += `|${v.option.identifier}_${http[v.option.identifier] || 0}`;
        }
    }
    // console.log(url);
    return url;
};

/*
 *比较数组是否完全相同
 */
global.a2a = function(a1, a2) {
    if (!(think.isArray(a1) && think.isArray(a2))) {
        return false;
    }
    if (a1.length !== a2.length) {
        return false;
    }

    a1.sort();
    a2.sort();
    for (let i = 0; i < a1.length; i++) {
        if (typeof a1[i] !== typeof a2[i]) {
            return false;
        }
        if (think.isObject(a1[i]) && think.isObject(a2[i])) {
            // eslint-disable-next-line no-undef
            const retVal = o2o(a1[i], a2[i]);
            if (!retVal) {
                return false;
            }
        } else if (think.isArray(a1[i]) && think.isArray(a2[i])) { // recursion
            // eslint-disable-next-line no-undef
            if (!a2a(a1[i], a2[i])) {
                return false;
            }
        } else if (a1[i] !== a2[i]) {
            return false;
        }
    }
    return true;
};

// 生成6位的随机数
global.MathRand = function() {
    let Num = '';
    for (let i = 0; i < 6; i++) {
        Num += Math.floor(Math.random() * 10);
    }
    return Num;
};

// 更新缓存
global.update_cache = async type => {
    switch (type) {
    case 'category':
        // 更新栏目缓存
        await think.cache('sys_category_list', null);
        await think.cache('all_category', null);
        await think.cache('all_priv', null);// 栏目权限缓存
        break;
    case 'channel':// 更新频道缓存信息
        await think.cache('get_channel_cache', null);
        break;
    case 'model':
        await think.cache('get_document_model', null);// 清除模型缓存
        await think.cache('get_model', null);// 清除模型缓存
        break;
    case 'ext':
        await think.cache('extcache', null);
        break;
    case 'hooks':
        await think.cache('hookscache', null);
        break;
    default:
    }
};

/**
 * 缓存权限列表 all_priv
 * @param {*} catid 要验证的栏目id
 * @param {*} roleid 用户组
 * @param {*} action 权限类型
 * @param {*} is_admin 谁否前台 0前台，1后台
 * @param {*} type true
 * @return {bool} 返回flase 或true false:没权限，true:有权限。
 */
global.priv = async (catid, roleid, action, is_admin = 0, type = true) => {
    const priv = await think.model('cmswing/category_priv').priv(catid, roleid, action, is_admin, type);
    // console.log(priv);
    if (!priv) {
        return false;
    }
    return true;

};

global.GetDateStr = function(AddDayCount) {
    const dd = new Date();
    dd.setDate(dd.getDate() + AddDayCount);// 获取AddDayCount天后的日期
    const y = dd.getFullYear();
    const m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1);// 获取当前月份的日期，不足10补0
    const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate();// 获取当前几号，不足10补0
    return y + '-' + m + '-' + d;
};

// 转意符换成普通字符
global.escape2Html = function(str) {
    const arrEntities = { lt: '<', gt: '>', nbsp: ' ', amp: '&', quot: '"' };
    return str.replace(/&(lt|gt|nbsp|amp|quot);/ig, function(all, t) { return arrEntities[t]; });
};

global.html_decode = function(str) {
    let s = '';
    if (str.length === 0) return '';
    s = str.replace(/&gt;/g, '&');
    s = s.replace(/&lt;/g, '<');
    s = s.replace(/&gt;/g, '>');
    s = s.replace(/&nbsp;/g, ' ');
    s = s.replace(/&#39;/g, "\'");
    s = s.replace(/&quot;/g, '"');
    s = s.replace(/<br>/g, '\n');
    return s;
};

global.html_encode = function(str) {
    let s = '';
    if (str.length === 0) return '';
    s = str.replace(/&/g, '&gt;');
    s = s.replace(/</g, '&lt;');
    s = s.replace(/>/g, '&gt;');
    s = s.replace(/ /g, '&nbsp;');
    s = s.replace(/\'/g, '&#39;');
    s = s.replace(/\"/g, '&quot;');
    s = s.replace(/\n/g, '<br>');
    return s;
};

/**
 * 检查pos(推荐位的值)是否包含指定推荐位contain
 * @param {number} pos 推荐位的值
 * @param {number} contain 指定推荐位
 * @return {boolean} true 包含 ， false 不包含
 */
global.check_document_position = (pos = 0, contain = 0) => {
    if (think.isEmpty(pos) || think.isEmpty(contain)) {
        return false;
    }
    // 将两个参数进行按位与运算，不为0则表示$contain属于$pos
    const res = pos & contain;
    if (res != 0) {
        return true;
    }
    return false;

};
